﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;

namespace Scenario_Editor.AddinManager
{
    public class AddinManagerScenarioEditor
    {
        #region Public Fields

        public IAddinScenarioEditor currentAddin;

        #endregion Public Fields

        #region Private Fields

        private CompositionContainer _container;

        private Dictionary<string, IAddinScenarioEditor> gameDlls;

        [ImportMany(typeof(IAddinScenarioEditor))]
        private IAddinScenarioEditor[] GameDlls;

        private global::Engine.Graphics.MaterialManager materialManager;

        private Scenario_Editor.Tools.Terrain.Terrain terrain;

        #endregion Private Fields

        #region Public Constructors

        public AddinManagerScenarioEditor(Engine.Engine Engine)
        {
            this.Engine = Engine;

            AggregateCatalog aggregateCatalog = new AggregateCatalog();

            var typeCatalog = new TypeCatalog(typeof(IAddinScenarioEditor));
            aggregateCatalog.Catalogs.Add(typeCatalog);
            var directoryCatalog = new DirectoryCatalog(".\\Addins", "*.GameDll.dll");
            aggregateCatalog.Catalogs.Add(directoryCatalog);

            this._container = new CompositionContainer(aggregateCatalog);

            //Create the CompositionContainer with the parts in the catalog
            this._container = new CompositionContainer(aggregateCatalog);

            //Fill the imports of this object
            try
            {
                this._container.ComposeParts(this);

                // Add interfaces to dictionary
                this.gameDlls = new Dictionary<string, IAddinScenarioEditor>();
                foreach (var item in this.GameDlls)
                {
                    this.gameDlls.Add(item.GetGameName(), item);
                }
            }
            catch (System.Reflection.ReflectionTypeLoadException ex)
            {
                Console.WriteLine(ex.Message);
            }
            catch (CompositionException compositionException)
            {
                Console.WriteLine(compositionException.ToString());
            }
        }

        internal IEnumerable<string> GetAddinNames()
        {
            List<string> addinnames = new List<string>();

            foreach (var item in this.GameDlls)
            {
                addinnames.Add(item.GetGameName());
            }

            return addinnames;
        }

        #endregion Public Constructors

        #region Public Events

        public event EventHandler CurrentAddinChanged;

        #endregion Public Events

        #region Public Properties

        public IAddinScenarioEditor CurrentAddin
        {
            get
            {
                return this.currentAddin;
            }
            set
            {
                this.currentAddin = value;

                if (this.CurrentAddinChanged != null)
                    this.CurrentAddinChanged(this.currentAddin, null);
            }
        }

        [Export("MainEngine")]
        private Engine.Engine Engine { get; set; }

        #endregion Public Properties

        #region Public Methods

        public IAddinScenarioEditor GetAddin(string gameDllName)
        {
            IAddinScenarioEditor addin;
            if (this.gameDlls.TryGetValue(gameDllName, out addin))
                return addin;

            throw new Exception("Game Dll not found: " + gameDllName);
        }

        #endregion Public Methods

        #region Internal Methods

        /// <summary>
        /// When Materialmanger is changed this Method must called.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void MaterialManagerChanged(object sender, EventArgs e)
        {
            this.materialManager = (Engine.Graphics.MaterialManager)sender;
            CurrentAddin.OnMaterialMangerChanged(sender, e);
        }

        internal void OnCurrentAddinChanged(object sender, EventArgs e)
        {
            this.CurrentAddin.OnTerrainChanged(this.terrain, e);
            CurrentAddin.OnMaterialMangerChanged(sender, e);
        }

        /// <summary>
        /// if new Terrain is created this Method should be called.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void OnTerrainChanged(object sender, EventArgs e)
        {
            this.terrain = (Scenario_Editor.Tools.Terrain.Terrain)sender;

            this.CurrentAddin.OnTerrainChanged(sender, e);
        }

        #endregion Internal Methods
    }
}